package org.example.uhy.domain.model.upgrade.execution.builder;


import org.example.uhy.domain.model.upgrade.execution.UpgradeExecutionTree;
import org.example.uhy.domain.model.upgrade.execution.node.LogicalExecutionNode;
import org.example.uhy.domain.model.upgrade.execution.node.UpgradeExecutionNode;
import org.example.uhy.domain.model.upgrade.schema.UpgradeRule;
import org.example.uhy.domain.model.upgrade.schema.UpgradeRuleId;
import org.example.uhy.domain.model.upgrade.schema.UpgradeSchema;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class UpgradeSchemaParser {
    public UpgradeExecutionTree parse(UpgradeSchema schema, UpgradeExecutionNodeFactory factory) {
        if (!schema.hasUpgradeRule()) {
            return null;
        }
        Map<UpgradeRuleId, UpgradeExecutionNode> nodeMap = createUpgradeExecutionNodes(schema.ruleIterator(), factory);
        UpgradeExecutionTree tree = buildGradeExecutionTree(schema.ruleIterator(), nodeMap);
        return tree;
    }

    private Map<UpgradeRuleId, UpgradeExecutionNode> createUpgradeExecutionNodes(Iterator<UpgradeRule> ruleIterator, UpgradeExecutionNodeFactory factory) {
        Map<UpgradeRuleId, UpgradeExecutionNode> nodeMap = new HashMap<>();
        while (ruleIterator.hasNext()) {
            UpgradeRule rule = ruleIterator.next();
            UpgradeExecutionNode node = factory.createUpgradeExecutionNode(rule);
            nodeMap.put(rule.ruleId(), node);
        }
        return nodeMap;
    }

    private UpgradeExecutionTree buildGradeExecutionTree(Iterator<UpgradeRule> ruleIterator, Map<UpgradeRuleId, UpgradeExecutionNode> nodeMap) {
        UpgradeExecutionNode root = null;
        while (ruleIterator.hasNext()) {
            UpgradeRule rule = ruleIterator.next();
            if (!rule.parentRuleId().isPresent()) {
                root = nodeMap.get(rule.ruleId());
            } else {
                LogicalExecutionNode parentNode = (LogicalExecutionNode) nodeMap.get(rule.parentRuleId().get());
                parentNode.addChild(nodeMap.get(rule.ruleId()));
            }
        }
        return new UpgradeExecutionTree(root);
    }
}
